

/**
 * @file CSSimulate.cpp
 */

//============================================================================
//
//  Shoujian Zhang - Wuhan University, 2012
//
//  program to simulate cycle slips for given satellite and given size 
//
//============================================================================


#include "CSSimulate.hpp"
#include "constants.hpp"

using namespace std;

namespace gpstk
{

      // Return a string identifying this object.
    std::string CSSimulate::getClassName() const
    { return "CSSimulate"; }



      /* Sets csInterval interval.
       *
       * @param interval      Sampling interval, in seconds.
       */
    CSSimulate& CSSimulate::setCSInterval(const double interval)
    {

         // Make sure that sample interval is positive
        if( interval >= 0.0 )
        {
            csInterval = interval;
        }

        return (*this);

    }  // End of method 'CSSimulate::setSampleInterval()'



      /* Sets tolerance, in seconds.
       *
       * @param tol                 Tolerance, in seconds.
       */
    CSSimulate& CSSimulate::setTolerance(const double tol)
    {

         // Make sure that tolerance is positive
        if( tol >= 0.0 )
        {
            tolerance = tol;
        }

        return (*this);

    }  // End of method 'CSSimulate::setTolerance()'


      /* Return a satTypeValueMap object, adding the new data generated when
       * calling this object.
       *
       * @param time      Epoch corresponding to the data.
       * @param gData     Data object holding the data.
       * @author          shjzhang
       * @warning         The modified decimate avoids the wrong decimate when
       *                  there is a large data gap more than threshold, which
       *                  is not considered in the old version.
       */
    satTypeValueMap& CSSimulate::Process( const CommonTime& time,
                                          satTypeValueMap& gData )
        noexcept(false)
    {


         // Time offset relative to the intial epoch time
        double timeoffset( (time - initialTime) );

        if(firstTime)
        {
            CSGPSAccumL1 = 0.0;
            CSGPSAccumL2 = 0.0;
            CSGPSAccumL5 = 0.0;

            CSGALAccumL1 = 0.0;
            CSGALAccumL5 = 0.0;
            CSGALAccumL7 = 0.0;
            CSGALAccumL8 = 0.0;
            CSGALAccumL6 = 0.0;

            CSBDSAccumL2 = 0.0;
            CSBDSAccumL7 = 0.0;
            CSBDSAccumL6 = 0.0;
           
            firstTime = false;

        }

        cout << "timeoffset" << timeoffset << endl;
        cout << (int)(timeoffset) % (int)(csInterval) << endl;

         // Check if current epoch is whether or not in the integer sampling
         // position with tolerance error.
         // if not, it will be decimated

         // CSSimulate the data with time earlier than the given initial time
        if ( timeoffset < 0.0)
        {
            return gData;
        }
        else if ( (int)(timeoffset) % (int)(csInterval) == 0  )
        {
            // find the satellite
            auto iter = gData.find(csSat);
            if( iter != gData.end() )
            {
                if(csSat.system == SatelliteSystem::GPS)
                {
                    if( (*iter).second.find(TypeID::L1C) != (*iter).second.end() );
                    {
                        CSGPSAccumL1 += CSGPSL1; 
                    }

                    if( (*iter).second.find(TypeID::L2W) != (*iter).second.end() );
                    {
                        CSGPSAccumL2 += CSGPSL2; 
                    }

                    if( (*iter).second.find(TypeID::L5X) != (*iter).second.end() );
                    {
                        CSGPSAccumL5 += CSGPSL5; 
                    }
                }
                else if(csSat.system == SatelliteSystem::Galileo)
                {
                    if( (*iter).second.find(TypeID::L1X) != (*iter).second.end() );
                    {
                        CSGALAccumL1 += CSGALL1; 
                    }

                    if( (*iter).second.find(TypeID::L5X) != (*iter).second.end() );
                    {
                        CSGALAccumL5 += CSGALL5; 
                    }

                    if( (*iter).second.find(TypeID::L7X) != (*iter).second.end() );
                    {
                        CSGALAccumL7 += CSGALL7; 
                    }

                    if( (*iter).second.find(TypeID::L8X) != (*iter).second.end() );
                    {
                        CSGALAccumL8 += CSGALL8; 
                    }

                    if( (*iter).second.find(TypeID::L6X) != (*iter).second.end() );
                    {
                        CSGALAccumL6 += CSGALL6; 
                    }
                }
                else if(csSat.system == SatelliteSystem::BDS)
                {
                    if( (*iter).second.find(TypeID::L2I) != (*iter).second.end() );
                    {
                        CSBDSAccumL2 += CSBDSL2; 
                    }

                    if( (*iter).second.find(TypeID::L7I) != (*iter).second.end() );
                    {
                        CSBDSAccumL7 += CSBDSL7; 
                    }

                    if( (*iter).second.find(TypeID::L6I) != (*iter).second.end() );
                    {
                        CSBDSAccumL6 += CSBDSL6; 
                    }
                }
                else if(csSat.system == SatelliteSystem::GLONASS)
                {
                    // to be done
                }

                if(sumStream!=NULL)
                {
                    (*sumStream) 
                        << csSat << " " 
                        << YDSTime(time)  << " "
                        << CSGPSAccumL1 << " "
                        << CSGPSAccumL2 << " "
                        << CSGPSAccumL5 << " "
                        << endl;;
                }
            }
        }

        // now, let's add the accumulated cycle slips into carrier-phase observations

        // find the satellite
        auto iter = gData.find(csSat);
        if( iter != gData.end())
        {
            if(csSat.system == SatelliteSystem::GPS)
            {
                if( (*iter).second.find(TypeID::L1C) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L1C] += L1_WAVELENGTH_GPS*CSGPSAccumL1; 
                }

                if( (*iter).second.find(TypeID::L2W) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L2W] += L2_WAVELENGTH_GPS*CSGPSAccumL2; 
                }

                if( (*iter).second.find(TypeID::L5X) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L5X] += L5_WAVELENGTH_GPS*CSGPSAccumL5; 
                }
            }
            else if(csSat.system == SatelliteSystem::Galileo)
            {
                if( (*iter).second.find(TypeID::L1X) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L1X] += L1_WAVELENGTH_GAL*CSGALAccumL1; 
                }

                if( (*iter).second.find(TypeID::L5X) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L5X] += L5_WAVELENGTH_GAL*CSGALAccumL5; 
                }

                if( (*iter).second.find(TypeID::L7X) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L7X] += L7_WAVELENGTH_GAL*CSGALAccumL7; 
                }

                if( (*iter).second.find(TypeID::L6X) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L6X] += L6_WAVELENGTH_GAL*CSGALAccumL6; 
                }
            }
            else if(csSat.system == SatelliteSystem::BDS)
            {
                if( (*iter).second.find(TypeID::L2I) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L2I] += L2_WAVELENGTH_BDS*CSBDSAccumL2; 
                }

                if( (*iter).second.find(TypeID::L7I) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L7I] += L7_WAVELENGTH_BDS*CSBDSAccumL7; 
                }

                if( (*iter).second.find(TypeID::L6I) != (*iter).second.end() );
                {
                    (*iter).second[TypeID::L6I] += L6_WAVELENGTH_BDS*CSBDSAccumL6; 
                }
            }


        }

        return gData;

    }  // End of method 'CSSimulate::Process()'


     /** Return a sourceRinex object, adding the new data generated
      *  when calling this object.
      *
      * @param gData    Data object holding the data.
      */
    void CSSimulate::Process(commonHeader& comHeader,sourceRinex& gData)
        noexcept(false)
    {

        for(sourceDataMap::iterator sdmIt = gData.body.begin();
            sdmIt != gData.body.end();
            ++sdmIt)
        {
            Process( gData.header.epoch, sdmIt->second );
        }


    }  // End of method 'CSSimulate::Process()'

}  // End of namespace gpstk
